package seedmarket

import org.springframework.dao.DataIntegrityViolationException

/**
 * The User controller for the database
 * @author Gregory Koutrelakos
 * @version 7.11.12
 *
 */
class UserController {
	//a counter for login attempts
	static int count = 0

	/**
	 * Allows all methods to be accessed currently
	 */
    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

	/**
	 * Default method that will be called. Will redirect to the show user page 
	 * @return
	 */
    def index() {
        redirect(action: "show", params: params)
    }
	
	/**
	 * Represents when the user will be locked out of the system
	 */
	def lockout = {}
	
	/**
	 * Changes count to 0 when account is unlocked
	 */
	def unlocked = {
		count = 0
	}
	
	/**
	 * Represents when a user logs into the system
	 */
	def login = {}
	
	/**
	 * Authenticates the user by looking them up in the database. Searches for the user then checks to see if they've been locked out
	 * already. Displays messages and allows login
	 */
	def authenticate = {
		def user = User.findByUserNameAndPassword(params.userName, params.password)
		if(count < 3) {
			if(user){ //checks if user is valid and not locked out. aslo resets count
				count = 0
				session.user = user
				flash.message = "Hello ${user.fullName}!"
				redirect(controller:"seed", action:"list")
				
			}
			else{ //increments the counter for a failed login attempt
			count++
			flash.message = "Sorry, ${params.userName}. Please try again."
			redirect(action:"login")
			}
		}
		else { //locks out
			redirect(action:"lockout")
			
		}
	}
	
	/**
	 * Logs the user out of the system. Searches for the current user and displays goodbye message
	 */
	def logout = {
		def user = User.findByUserNameAndPassword(params.userName, params.password)
		if(user) {
			flash.message = "Goodbye ${session.user.fullName}"
			session.user = null
			redirect(action:"login")
		}
		else {
			flash.message = "Sorry, you need to log in first."
			redirect(action:"login")
		}
	}

	/**
	 * Lists the users in the database 
	 * @return a list of the users
	 */
    def list() {
        params.max = Math.min(params.max ? params.int('max') : 10, 100)
        [userInstanceList: User.list(params), userInstanceTotal: User.count()]
    }

	/**
	 * Creates a new user instance
	 * @return new user instance
	 */
    def create() {
        [userInstance: new User(params)]
    }

	/**
	 * Saves the user to the system then shows the user
	 * @return the saved user
	 */
    def save() {
		//new user instance and checks if valid
        def userInstance = new User(params)
        if (!userInstance.save(flush: true)) {
            render(view: "create", model: [userInstance: userInstance])
            return
        }

		flash.message = message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])
        redirect(action: "show", id: userInstance.id)
    }

	/**
	 * Shows the user if found
	 * @return the current user
	 */
    def show() {
        def userInstance = User.get(params.id)
        if (!userInstance) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "list")
            return
        }

        [userInstance: userInstance]
    }

	/**
	 * Edits the current user after searching for the valid instance. Is used in update so return null
	 * @return null
	 */
    def edit() {
        def userInstance = User.get(params.id)
        if (!userInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "list")
            return
        }

        [userInstance: userInstance]
    }

	/**
	 * Updates the user based upon the edited parameters. Checks for validity and creates new instance.
	 * @return the updated/edited user
	 */
    def update() {
        def userInstance = User.get(params.id)
        if (!userInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "list")
            return
        }

        if (params.version) {
            def version = params.version.toLong()
            if (userInstance.version > version) {
                userInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
                          [message(code: 'user.label', default: 'User')] as Object[],
                          "Another user has updated this User while you were editing")
                render(view: "edit", model: [userInstance: userInstance])
                return
            }
        }

        userInstance.properties = params

        if (!userInstance.save(flush: true)) {
            render(view: "edit", model: [userInstance: userInstance])
            return
        }

		flash.message = message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])
        redirect(action: "show", id: userInstance.id)
    }

	/**
	 * Deletes a user. Checks if user is valid then tries to remove if able
	 * @return deleted user
	 */
    def delete() {
        def userInstance = User.get(params.id)
        if (!userInstance) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "list")
            return
        }

        try {
            userInstance.delete(flush: true)
			flash.message = message(code: 'default.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "list")
        }
        catch (DataIntegrityViolationException e) {
			flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'user.label', default: 'User'), params.id])
            redirect(action: "show", id: params.id)
        }
    }
}
